package shlib

import (
	"fmt"
	"os"
)

const (
	LOG_LEVEL_DEBUG = iota
	LOG_LEVEL_INFO
	LOG_LEVEL_WARN
	LOG_LEVEL_ERROR
	LOG_LEVEL_FATAL
)

var levelChar = []rune{'D', 'I', 'W', 'E', 'F'}

func defaultLogHeadFunc(level int, callerDepth int) string {
	return fmt.Sprintf("%s [%c] %s:", NowString(), levelChar[level], Caller(callerDepth))
}

var defaultLogger = Logger{
	headFunc:    defaultLogHeadFunc,
	outputLevel: LOG_LEVEL_DEBUG,
	writer:      &StdoutLogWriter{},
}

func DefaultLogger() *Logger {
	return &defaultLogger
}

//=============================================================================

type LogHeadFunc func(level int, callerDepth int) string

type LogWriter interface {
	Open(options interface{})
	Close()
	Write(head string, args ...interface{})
}

type StdoutLogWriter struct {
	// Nothing
}

func (this *StdoutLogWriter) Open(options interface{}) {
	// Nothing
}

func (this *StdoutLogWriter) Close() {
	// Nothing
}

func (this *StdoutLogWriter) Write(head string, args ...interface{}) {
	var buf [1024]byte
	xb := XBuf{buf[:], 0, 0, true}

	xb.PutStr(head)
	for _, arg := range args {
		xb.PutByte(byte(' '))
		xb.PutStr(fmt.Sprintf("%v", arg))
	}
	xb.PutByte(byte('\n'))

	os.Stdout.Write(xb.Bytes())
}

//=============================================================================

type Logger struct {
	headFunc    LogHeadFunc
	outputLevel int
	writer      LogWriter
}

func (this *Logger) Log(level int, args ...interface{}) {
	if level >= this.outputLevel {
		this.writer.Write(this.headFunc(level, 3), args...)
	}
}

func (this *Logger) Logf(level int, format string, args ...interface{}) {
	if level >= this.outputLevel {
		this.writer.Write(this.headFunc(level, 3), fmt.Sprintf(format, args...))
	}
}

func (this *Logger) Logfe(level int, err error, format string, args ...interface{}) {
	if level >= this.outputLevel {
		this.writer.Write(this.headFunc(level, 3), fmt.Sprintf(format, args...), "\n\t", err)
	}
}

func (this *Logger) Debug(args ...interface{}) {
	if LOG_LEVEL_DEBUG >= this.outputLevel {
		this.writer.Write(this.headFunc(LOG_LEVEL_DEBUG, 3), args...)
	}
}

func (this *Logger) Debugf(format string, args ...interface{}) {
	if LOG_LEVEL_DEBUG >= this.outputLevel {
		this.writer.Write(this.headFunc(LOG_LEVEL_DEBUG, 3), fmt.Sprintf(format, args...))
	}
}

func (this *Logger) Debugfe(err error, format string, args ...interface{}) {
	if LOG_LEVEL_DEBUG >= this.outputLevel {
		this.writer.Write(this.headFunc(LOG_LEVEL_DEBUG, 3), fmt.Sprintf(format, args...), "\n\t", err)
	}
}

func (this *Logger) Info(args ...interface{}) {
	if LOG_LEVEL_INFO >= this.outputLevel {
		this.writer.Write(this.headFunc(LOG_LEVEL_INFO, 3), args...)
	}
}

func (this *Logger) Infof(format string, args ...interface{}) {
	if LOG_LEVEL_INFO >= this.outputLevel {
		this.writer.Write(this.headFunc(LOG_LEVEL_INFO, 3), fmt.Sprintf(format, args...))
	}
}

func (this *Logger) Infofe(err error, format string, args ...interface{}) {
	if LOG_LEVEL_INFO >= this.outputLevel {
		this.writer.Write(this.headFunc(LOG_LEVEL_INFO, 3), fmt.Sprintf(format, args...), "\n\t", err)
	}
}

func (this *Logger) Warn(args ...interface{}) {
	if LOG_LEVEL_WARN >= this.outputLevel {
		this.writer.Write(this.headFunc(LOG_LEVEL_WARN, 3), args...)
	}
}

func (this *Logger) Warnf(format string, args ...interface{}) {
	if LOG_LEVEL_WARN >= this.outputLevel {
		this.writer.Write(this.headFunc(LOG_LEVEL_WARN, 3), fmt.Sprintf(format, args...))
	}
}

func (this *Logger) Warnfe(err error, format string, args ...interface{}) {
	if LOG_LEVEL_WARN >= this.outputLevel {
		this.writer.Write(this.headFunc(LOG_LEVEL_WARN, 3), fmt.Sprintf(format, args...), "\n\t", err)
	}
}

func (this *Logger) Error(args ...interface{}) {
	if LOG_LEVEL_ERROR >= this.outputLevel {
		this.writer.Write(this.headFunc(LOG_LEVEL_ERROR, 3), args...)
	}
}

func (this *Logger) Errorf(format string, args ...interface{}) {
	if LOG_LEVEL_ERROR >= this.outputLevel {
		this.writer.Write(this.headFunc(LOG_LEVEL_ERROR, 3), fmt.Sprintf(format, args...))
	}
}

func (this *Logger) Errorfe(err error, format string, args ...interface{}) {
	if LOG_LEVEL_ERROR >= this.outputLevel {
		this.writer.Write(this.headFunc(LOG_LEVEL_ERROR, 3), fmt.Sprintf(format, args...), "\n\t", err)
	}
}

func (this *Logger) Fatal(args ...interface{}) {
	if LOG_LEVEL_FATAL >= this.outputLevel {
		this.writer.Write(this.headFunc(LOG_LEVEL_FATAL, 3), args...)
		os.Exit(-1)
	}
}

func (this *Logger) Fatalf(format string, args ...interface{}) {
	if LOG_LEVEL_FATAL >= this.outputLevel {
		this.writer.Write(this.headFunc(LOG_LEVEL_FATAL, 3), fmt.Sprintf(format, args...))
		os.Exit(-1)
	}
}

func (this *Logger) Fatalfe(err error, format string, args ...interface{}) {
	if LOG_LEVEL_FATAL >= this.outputLevel {
		this.writer.Write(this.headFunc(LOG_LEVEL_FATAL, 3), fmt.Sprintf(format, args...), "\n\t", err)
		os.Exit(-1)
	}
}
